aviutl2\generic\binding/
host_app.rs

1use crate::{AviUtl2Info, generic::EditSection};
2use pastey::paste;
3use std::num::NonZeroIsize;
4
5/// ホストアプリケーションのハンドル。
6/// プラグインの初期化処理で使用します。
7///
8/// # Panics
9///
10/// この型がプラグインの初期化処理の外で使用された場合はPanicします。
11pub struct HostAppHandle<'a> {
12    internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
13    global_leak_manager: &'a mut crate::common::LeakManager,
14    kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
15    plugin_registry: &'a mut crate::generic::PluginRegistry,
16}
17
18/// プラグインの初期化状態を管理するためのハンドル。
19pub struct SubPlugin<T> {
20    plugin: std::marker::PhantomData<T>,
21    internal: std::sync::Arc<InternalReferenceHandle>,
22}
23struct InternalReferenceHandle {
24    uninitialize_fn: fn(),
25}
26impl Drop for InternalReferenceHandle {
27    fn drop(&mut self) {
28        (self.uninitialize_fn)();
29    }
30}
31
32impl<'a> HostAppHandle<'a> {
33    pub(crate) unsafe fn new(
34        internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
35        global_leak_manager: &'a mut crate::common::LeakManager,
36        kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
37        plugin_registry: &'a mut crate::generic::PluginRegistry,
38    ) -> Self {
39        Self {
40            internal,
41            global_leak_manager,
42            kill_switch,
43            plugin_registry,
44        }
45    }
46
47    fn assert_not_killed(&self) {
48        if self.kill_switch.load(std::sync::atomic::Ordering::SeqCst) {
49            panic!("This HostAppHandle is no longer valid.");
50        }
51    }
52
53    /// プラグインの情報を設定します。
54    /// 「プラグイン情報」ダイアログで表示されます。
55    pub fn set_plugin_information(&mut self, information: &str) {
56        self.assert_not_killed();
57        let information = if cfg!(debug_assertions) {
58            format!("{information} (Debug Build)")
59        } else {
60            information.to_string()
61        };
62        unsafe {
63            ((*self.internal).set_plugin_information)(
64                self.global_leak_manager.leak_as_wide_string(&information),
65            )
66        }
67    }
68
69    /// プロジェクトデータ編集用のハンドルを登録します。
70    pub fn create_edit_handle(&mut self) -> crate::generic::EditHandle {
71        self.assert_not_killed();
72        let raw_handle = unsafe { ((*self.internal).create_edit_handle)() };
73        unsafe { crate::generic::EditHandle::new(raw_handle) }
74    }
75
76    /// インポートメニューを登録します。
77    ///
78    /// # See Also
79    ///
80    /// - [`crate::generic::menus`]
81    pub fn register_import_menu(
82        &mut self,
83        name: &str,
84        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
85    ) {
86        self.assert_not_killed();
87        unsafe {
88            ((*self.internal).register_import_menu)(
89                self.global_leak_manager.leak_as_wide_string(name),
90                callback,
91            )
92        }
93    }
94
95    /// エクスポートメニューを登録します。
96    ///
97    /// # See Also
98    ///
99    /// - [`crate::generic::menus`]
100    pub fn register_export_menu(
101        &mut self,
102        name: &str,
103        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
104    ) {
105        self.assert_not_killed();
106        unsafe {
107            ((*self.internal).register_export_menu)(
108                self.global_leak_manager.leak_as_wide_string(name),
109                callback,
110            )
111        }
112    }
113
114    /// レイヤーメニューを登録します。
115    /// レイヤー編集でオブジェクト未選択時の右クリックメニューに追加されます。
116    ///
117    /// # See Also
118    ///
119    /// - [`crate::generic::menus`]
120    pub fn register_layer_menu(
121        &mut self,
122        name: &str,
123        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
124    ) {
125        self.assert_not_killed();
126        unsafe {
127            ((*self.internal).register_layer_menu)(
128                self.global_leak_manager.leak_as_wide_string(name),
129                callback,
130            )
131        }
132    }
133
134    /// オブジェクトメニューを登録します。
135    /// レイヤー編集でオブジェクト選択時の右クリックメニューに追加されます。
136    ///
137    /// # See Also
138    ///
139    /// - [`crate::generic::menus`]
140    pub fn register_object_menu(
141        &mut self,
142        name: &str,
143        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
144    ) {
145        self.assert_not_killed();
146        unsafe {
147            ((*self.internal).register_object_menu)(
148                self.global_leak_manager.leak_as_wide_string(name),
149                callback,
150            )
151        }
152    }
153
154    /// 編集メニューを登録します。
155    /// 名前に`\\`を含めるとサブメニューとして登録されます。
156    ///
157    /// # See Also
158    ///
159    /// - [`crate::generic::menus`]
160    pub fn register_edit_menu(
161        &mut self,
162        name: &str,
163        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
164    ) {
165        self.assert_not_killed();
166        unsafe {
167            ((*self.internal).register_edit_menu)(
168                self.global_leak_manager.leak_as_wide_string(name),
169                callback,
170            )
171        }
172    }
173
174    /// 設定メニューを登録します。
175    /// 設定メニューの登録後にウィンドウクライアントを登録するとシステムメニューに「設定」が追加されます。
176    ///
177    /// # See Also
178    ///
179    /// - [`crate::generic::menus`]
180    pub fn register_config_menu(
181        &mut self,
182        name: &str,
183        callback: extern "C" fn(aviutl2_sys::plugin2::HWND, aviutl2_sys::plugin2::HINSTANCE),
184    ) {
185        self.assert_not_killed();
186        unsafe {
187            ((*self.internal).register_config_menu)(
188                self.global_leak_manager.leak_as_wide_string(name),
189                callback,
190            )
191        };
192    }
193
194    /// ウィンドウクライアントを登録します。
195    ///
196    /// # Panics
197    ///
198    /// Win32のウィンドウハンドル以外が渡された場合はPanicします。
199    pub fn register_window_client<T: raw_window_handle::HasWindowHandle>(
200        &mut self,
201        name: &str,
202        instance: &T,
203    ) -> Result<(), raw_window_handle::HandleError> {
204        self.assert_not_killed();
205        let raw_handle = instance.window_handle()?;
206        let hwnd = match raw_handle.as_raw() {
207            raw_window_handle::RawWindowHandle::Win32(handle) => handle.hwnd,
208            _ => panic!("Only Win32WindowHandle is supported"),
209        };
210        unsafe {
211            ((*self.internal).register_window_client)(
212                self.global_leak_manager.leak_as_wide_string(name),
213                hwnd.get() as *mut std::ffi::c_void,
214            );
215        }
216        Ok(())
217    }
218
219    /// メニューを一括登録します。
220    ///
221    /// # See Also
222    ///
223    /// - [`crate::generic::menus`]
224    pub fn register_menus<T: GenericPluginMenus>(&mut self) {
225        self.assert_not_killed();
226        T::register_menus(self);
227    }
228
229    /// プロジェクトファイルをロードした直後に呼ばれる関数を登録します。
230    /// また、プロジェクトの初期化時にも呼ばれます。
231    ///
232    /// # Note
233    ///
234    /// [`crate::generic::GenericPlugin::on_project_load`] が自動的に登録されるため、
235    /// 通常はこの関数を直接使用する必要はありません。
236    pub fn register_project_load_handler(
237        &mut self,
238        callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE),
239    ) {
240        self.assert_not_killed();
241        unsafe {
242            ((*self.internal).register_project_load_handler)(callback);
243        }
244    }
245
246    /// プロジェクトファイルを保存する直前に呼ばれる関数を登録します。
247    ///
248    /// # Note
249    ///
250    /// [`crate::generic::GenericPlugin::on_project_save`] が自動的に登録されるため、
251    /// 通常はこの関数を直接使用する必要はありません。
252    pub fn register_project_save_handler(
253        &mut self,
254        callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE),
255    ) {
256        self.assert_not_killed();
257        unsafe {
258            ((*self.internal).register_project_save_handler)(callback);
259        }
260    }
261
262    /// 「キャッシュを破棄」が呼ばれたときに呼ばれる関数を登録します。
263    ///
264    /// # Note
265    ///
266    /// [`crate::generic::GenericPlugin::on_clear_cache`] が自動的に登録されるため、
267    /// 通常はこの関数を直接使用する必要はありません。
268    pub fn register_clear_cache_handler(
269        &mut self,
270        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
271    ) {
272        self.assert_not_killed();
273        unsafe {
274            ((*self.internal).register_clear_cache_handler)(callback);
275        }
276    }
277
278    /// シーンを変更した直後に呼ばれる関数を登録します。
279    ///
280    /// # Note
281    ///
282    /// [`crate::generic::GenericPlugin::on_change_scene`] が自動的に登録されるため、
283    /// 通常はこの関数を直接使用する必要はありません。
284    pub fn register_change_scene_handler(
285        &mut self,
286        callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
287    ) {
288        self.assert_not_killed();
289        unsafe {
290            ((*self.internal).register_change_scene_handler)(callback);
291        }
292    }
293}
294
295/// 汎用プラグインのメニュー登録用トレイト。
296///
297/// <div class="warning">
298///
299/// このトレイトは [`crate::generic::menus`] マクロで自動的に実装されます。
300/// 通常は手動で実装する必要はありません。
301///
302/// </div>
303pub trait GenericPluginMenus {
304    fn register_menus(host: &mut HostAppHandle);
305}
306
307#[doc(inline)]
308pub use aviutl2_macros::generic_menus as menus;
309
310#[derive(Default)]
311pub(crate) struct PluginRegistry {
312    #[cfg(feature = "input")]
313    input_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
314    #[cfg(feature = "output")]
315    output_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
316    #[cfg(feature = "filter")]
317    filter_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
318    #[cfg(feature = "module")]
319    script_modules: Vec<std::sync::Arc<InternalReferenceHandle>>,
320}
321impl PluginRegistry {
322    pub(crate) fn new() -> Self {
323        Self::default()
324    }
325}
326
327macro_rules! impl_plugin_registry {
328    (
329        $description:literal,
330        $feature:literal,
331        $module:ident,
332        $name:ident,
333        $register_method:ident,
334        $PluginTrait:path,
335        $SingletonTrait:path,
336        $TableType:ty
337    ) => {
338        paste! {
339            impl<T> SubPlugin<T> {
340                #[cfg(feature = $feature)]
341                #[doc = concat!($description, "の新しいインスタンスを作成します。")]
342                pub fn [<new_ $name>](info: AviUtl2Info) -> crate::AnyResult<Self>
343                where
344                    T: $PluginTrait + $SingletonTrait + 'static
345                {
346                    crate::$module::__bridge::initialize_plugin::<T>(info.version.into())?;
347                    let internal = std::sync::Arc::new(InternalReferenceHandle {
348                        uninitialize_fn: || {
349                            unsafe {
350                                crate::$module::__bridge::uninitialize_plugin::<T>();
351                            }
352                        },
353                    });
354                    Ok(Self {
355                        plugin: std::marker::PhantomData,
356                        internal,
357                    })
358                }
359            }
360            #[cfg(feature = $feature)]
361            impl<'a> HostAppHandle<'a> {
362                #[doc = concat!($description, "を登録します。")]
363                pub fn [<register_ $name>]<T: $PluginTrait + $SingletonTrait + 'static>(
364                    &mut self,
365                    handle: &SubPlugin<T>,
366                ) {
367                    self.assert_not_killed();
368                    unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table::<T>()) };
369                    self.plugin_registry
370                        .[<$name s>]
371                        .push(std::sync::Arc::clone(&handle.internal));
372                }
373            }
374        }
375    };
376}
377
378impl_plugin_registry!(
379    "入力プラグイン",
380    "input",
381    input,
382    input_plugin,
383    register_input_plugin,
384    crate::input::InputPlugin,
385    crate::input::__bridge::InputSingleton,
386    aviutl2_sys::input2::INPUT_PLUGIN_TABLE
387);
388impl_plugin_registry!(
389    "出力プラグイン",
390    "output",
391    output,
392    output_plugin,
393    register_output_plugin,
394    crate::output::OutputPlugin,
395    crate::output::__bridge::OutputSingleton,
396    aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE
397);
398impl_plugin_registry!(
399    "フィルタープラグイン",
400    "filter",
401    filter,
402    filter_plugin,
403    register_filter_plugin,
404    crate::filter::FilterPlugin,
405    crate::filter::__bridge::FilterSingleton,
406    aviutl2_sys::filter2::FILTER_PLUGIN_TABLE
407);
408impl_plugin_registry!(
409    "スクリプトモジュール",
410    "module",
411    module,
412    script_module,
413    register_script_module,
414    crate::module::ScriptModule,
415    crate::module::__bridge::ScriptModuleSingleton,
416    aviutl2_sys::module2::SCRIPT_MODULE_TABLE
417);
418
419/// 編集ハンドル。
420#[derive(Debug)]
421pub struct EditHandle {
422    pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE,
423}
424
425unsafe impl Send for EditHandle {}
426unsafe impl Sync for EditHandle {}
427
428/// [`EditHandle`] 関連のエラー。
429#[derive(thiserror::Error, Debug)]
430pub enum EditHandleError {
431    #[error("api call failed")]
432    ApiCallFailed,
433}
434
435impl EditHandle {
436    pub(crate) unsafe fn new(internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE) -> Self {
437        Self { internal }
438    }
439
440    /// プロジェクトデータの編集を開始します。
441    ///
442    /// # Note
443    ///
444    /// 内部では call_edit_section_param を使用しています。
445    pub fn call_edit_section<'a, T, F>(&self, callback: F) -> Result<T, EditHandleError>
446    where
447        T: Send + 'static,
448        F: FnOnce(&mut EditSection) -> T + Send + 'a,
449    {
450        type CallbackParam<'a, F, T> = (ChildKillablePointer<Option<F>>, &'a mut Option<T>);
451
452        let closure = Some(callback);
453        let param = KillablePointer::new(closure);
454        let child_param = param.create_child();
455
456        extern "C" fn trampoline<F, T>(
457            param: *mut std::ffi::c_void,
458            edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
459        ) where
460            T: Send + 'static,
461            F: FnOnce(&mut EditSection) -> T,
462        {
463            unsafe {
464                let (child_param, result_ptr) = &mut *(param as *mut CallbackParam<F, T>);
465                let callback = child_param
466                    .as_mut()
467                    .take()
468                    .expect("Callback has already been called");
469                let mut edit_section = EditSection::from_raw(edit_section);
470                let res = callback(&mut edit_section);
471
472                result_ptr.replace(res);
473            }
474        }
475
476        let trampoline_static = trampoline::<F, T>
477            as extern "C" fn(*mut std::ffi::c_void, *mut aviutl2_sys::plugin2::EDIT_SECTION);
478
479        let mut result = None;
480        let param = Box::<CallbackParam<F, T>>::new((child_param, &mut result));
481        let param_ptr = Box::into_raw(param);
482
483        let success = unsafe {
484            ((*self.internal).call_edit_section_param)(
485                param_ptr as *mut std::ffi::c_void,
486                trampoline_static,
487            )
488        };
489
490        if success {
491            Ok(result.expect("Callback did not set result"))
492        } else {
493            Err(EditHandleError::ApiCallFailed)
494        }
495    }
496
497    /// 編集情報を取得します。
498    ///
499    /// # Note
500    ///
501    /// 既に編集処理中(`call_edit_section` 内)である場合、デッドロックします。
502    pub fn get_edit_info(&self) -> crate::generic::EditInfo {
503        let mut raw_info = std::mem::MaybeUninit::<aviutl2_sys::plugin2::EDIT_INFO>::uninit();
504        unsafe {
505            ((*self.internal).get_edit_info)(
506                raw_info.as_mut_ptr(),
507                std::mem::size_of::<aviutl2_sys::plugin2::EDIT_INFO>() as _,
508            );
509            let edit_info = raw_info.assume_init();
510            crate::generic::EditInfo::from_raw(&edit_info)
511        }
512    }
513
514    /// ホストアプリケーションを再起動します。
515    pub fn restart_host_app(&self) {
516        unsafe {
517            ((*self.internal).restart_host_app)();
518        }
519    }
520
521    /// エフェクト名の一覧をコールバック関数で取得します。
522    pub fn enumerate_effect_names<F>(&self, mut callback: F)
523    where
524        F: FnMut(Effect),
525    {
526        extern "C" fn trampoline<F>(
527            param: *mut std::ffi::c_void,
528            name: aviutl2_sys::common::LPCWSTR,
529            r#type: i32,
530            flag: i32,
531        ) where
532            F: FnMut(Effect),
533        {
534            let callback = unsafe { &mut *(param as *mut F) };
535            let name_str = unsafe { crate::common::load_wide_string(name) };
536            let effect = Effect {
537                name: name_str,
538                effect_type: EffectType::from(r#type),
539                flag: EffectFlag::from_bits(flag),
540            };
541            callback(effect);
542        }
543
544        let trampoline_static = trampoline::<F>
545            as extern "C" fn(*mut std::ffi::c_void, aviutl2_sys::common::LPCWSTR, i32, i32);
546        let user_data = &mut callback as *mut F as *mut std::ffi::c_void;
547        unsafe {
548            ((*self.internal).enum_effect_name)(user_data, trampoline_static);
549        }
550    }
551
552    /// エフェクト名の一覧を取得します。
553    pub fn get_effect_names(&self) -> Vec<Effect> {
554        let mut effects = Vec::new();
555        self.enumerate_effect_names(|effect| {
556            effects.push(effect);
557        });
558        effects
559    }
560}
561
562/// エフェクト。
563pub struct Effect {
564    /// エフェクト名。
565    pub name: String,
566    /// エフェクト種別。
567    pub effect_type: EffectType,
568    /// フラグ。
569    pub flag: EffectFlag,
570}
571
572/// エフェクト種別。
573#[derive(Debug, Clone, Copy, PartialEq, Eq)]
574pub enum EffectType {
575    /// フィルタ効果。
576    Filter,
577    /// メディア入力。
578    Input,
579    /// シーンチェンジ。
580    SceneChange,
581    /// その他。
582    Other(i32),
583}
584
585define_bitflag! {
586    /// エフェクトのフラグ。
587    #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
588    #[non_exhaustive]
589    pub struct EffectFlag: i32 {
590        /// 画像フィルタをサポートするかどうか。
591        video: aviutl2_sys::plugin2::EDIT_HANDLE::EFFECT_FLAG_VIDEO,
592
593        /// 音声フィルタをサポートするかどうか。
594        audio: aviutl2_sys::plugin2::EDIT_HANDLE::EFFECT_FLAG_AUDIO,
595
596        /// フィルタオブジェクトをサポートするかどうか。
597        as_filter: aviutl2_sys::plugin2::EDIT_HANDLE::EFFECT_FLAG_FILTER,
598    }
599}
600
601impl From<i32> for EffectType {
602    fn from(value: i32) -> Self {
603        match value {
604            0 => EffectType::Filter,
605            1 => EffectType::Input,
606            2 => EffectType::SceneChange,
607            other => EffectType::Other(other),
608        }
609    }
610}
611impl From<EffectType> for i32 {
612    fn from(value: EffectType) -> Self {
613        match value {
614            EffectType::Filter => 0,
615            EffectType::Input => 1,
616            EffectType::SceneChange => 2,
617            EffectType::Other(other) => other,
618        }
619    }
620}
621
622#[doc(hidden)]
623pub unsafe fn __internal_rwh_from_raw(
624    hwnd: aviutl2_sys::plugin2::HWND,
625    hinstance: aviutl2_sys::plugin2::HINSTANCE,
626) -> raw_window_handle::Win32WindowHandle {
627    let mut handle =
628        raw_window_handle::Win32WindowHandle::new(NonZeroIsize::new(hwnd as isize).unwrap());
629    handle.hinstance = Some(NonZeroIsize::new(hinstance as isize).unwrap());
630    handle
631}
632
633#[doc(hidden)]
634#[expect(private_bounds)]
635pub fn __output_log_if_error<T: MenuCallbackReturn>(result: T) {
636    if let Some(err_msg) = result.into_optional_error() {
637        let _ = crate::logger::write_error_log(&err_msg);
638    }
639}
640
641#[doc(hidden)]
642#[expect(private_bounds)]
643pub fn __alert_if_error<T: MenuCallbackReturn>(result: T) {
644    if let Some(err_msg) = result.into_optional_error() {
645        crate::common::alert_error(&anyhow::anyhow!(err_msg));
646    }
647}
648
649trait MenuCallbackReturn {
650    fn into_optional_error(self) -> Option<String>;
651}
652impl<E> MenuCallbackReturn for Result<(), E>
653where
654    Box<dyn std::error::Error>: From<E>,
655{
656    fn into_optional_error(self) -> Option<String> {
657        match self {
658            Ok(_) => None,
659            Err(e) => {
660                let boxed: Box<dyn std::error::Error> = e.into();
661                Some(format!("{}", boxed))
662            }
663        }
664    }
665}
666impl MenuCallbackReturn for () {
667    fn into_optional_error(self) -> Option<String> {
668        None
669    }
670}
671
672struct KillablePointer<T> {
673    kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
674    inner: *mut T,
675}
676unsafe impl<T> Send for KillablePointer<T> {}
677unsafe impl<T> Sync for KillablePointer<T> {}
678impl<T> Drop for KillablePointer<T> {
679    fn drop(&mut self) {
680        self.kill_switch
681            .store(true, std::sync::atomic::Ordering::SeqCst);
682    }
683}
684impl<T> KillablePointer<T> {
685    pub fn new(inner: T) -> Self {
686        Self {
687            kill_switch: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
688            inner: Box::into_raw(Box::new(inner)),
689        }
690    }
691
692    pub fn create_child(&self) -> ChildKillablePointer<T> {
693        ChildKillablePointer {
694            kill_switch: std::sync::Arc::clone(&self.kill_switch),
695            inner: self.inner,
696        }
697    }
698}
699
700struct ChildKillablePointer<T> {
701    kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
702    inner: *mut T,
703}
704unsafe impl<T> Send for ChildKillablePointer<T> {}
705unsafe impl<T> Sync for ChildKillablePointer<T> {}
706impl<T> ChildKillablePointer<T> {
707    pub fn is_killed(&self) -> bool {
708        self.kill_switch.load(std::sync::atomic::Ordering::SeqCst)
709    }
710
711    pub unsafe fn as_mut(&mut self) -> &mut T {
712        if self.is_killed() {
713            panic!("parent KillablePointer has been dropped");
714        }
715        unsafe { &mut *self.inner }
716    }
717}